package com.icongyou.enterprise.talent_pool.service;

import com.icongyou.enterprise.talent_pool.entity.AssignmentTagEntity;
import com.icongyou.enterprise.talent_pool.entity.TagEntity;
import com.icongyou.enterprise.talent_pool.mapper.AssignmentTagMapper;
import com.icongyou.enterprise.talent_pool.mapper.TagMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class TagProcessingServiceTest {

    @Mock
    private TagMapper tagMapper;

    @Mock
    private AssignmentTagMapper assignmentTagMapper;

    @Mock
    private TagRelevanceCalculationService relevanceCalculationService;

    @InjectMocks
    private TagProcessingService tagProcessingService;

    private TagEntity existingTag;
    private TagEntity newTag;
    private String tagId;
    private String tagName;

    @BeforeEach
    void setUp() {
        tagId = UUID.randomUUID().toString();
        tagName = "Java开发";

        existingTag = new TagEntity();
        existingTag.setTagId(tagId);
        existingTag.setTagName(tagName);
        existingTag.setIsActive(1);
        existingTag.setCreatedTime(LocalDateTime.now());

        newTag = new TagEntity();
        newTag.setTagId(UUID.randomUUID().toString());
        newTag.setTagName("新的标签");
        newTag.setIsActive(1);
        newTag.setCreatedTime(LocalDateTime.now());
    }

    @Test
    void processGeneratedTag_WhenTagExists_ShouldReturnExistingTagId() {
        // Arrange
        when(tagMapper.getTagByName(tagName)).thenReturn(existingTag);

        // Act
        String result = tagProcessingService.processGeneratedTag(tagName, null);

        // Assert
        assertEquals(tagId, result);
        verify(tagMapper, times(1)).getTagByName(tagName);
        verify(tagMapper, never()).insertTag(any());
        verify(relevanceCalculationService, never()).calculateTagForAllAssignments(anyString(), anyString());
    }

    @Test
    void processGeneratedTag_WhenTagNotExistsButHasSimilarTag_ShouldCreateNewTagAndCopyRelations() {
        // Arrange
        String similarTagName = "Java编程";
        String similarTagId = UUID.randomUUID().toString();
        String newTagId = UUID.randomUUID().toString();

        TagEntity similarTag = new TagEntity();
        similarTag.setTagId(similarTagId);
        similarTag.setTagName(similarTagName);

        AssignmentTagEntity assignmentTag = new AssignmentTagEntity();
        assignmentTag.setId(UUID.randomUUID().toString());
        assignmentTag.setAssignmentId("assignment-1");
        assignmentTag.setTagId(similarTagId);
        assignmentTag.setRelevance(0.8);
        assignmentTag.setAssignmentWeight(1.0);

        List<AssignmentTagEntity> similarAssignmentTags = Arrays.asList(assignmentTag);

        when(tagMapper.getTagByName(tagName)).thenReturn(null);
        when(tagMapper.getTagByName(similarTagName)).thenReturn(similarTag);
        when(tagMapper.insertTag(any(TagEntity.class))).thenReturn(1); // 修复：直接返回1
        when(assignmentTagMapper.getAssignmentTagsByTagId(similarTagId)).thenReturn(similarAssignmentTags);
        // 修复：使用 doNothing() 来模拟 void 方法
        doNothing().when(assignmentTagMapper).batchInsertAssignmentTags(anyList());

        // Act
        String result = tagProcessingService.processGeneratedTag(tagName, Arrays.asList(similarTagName));

        // Assert
        assertNotNull(result);
        verify(tagMapper, times(1)).getTagByName(tagName);
        verify(tagMapper, times(1)).getTagByName(similarTagName);
        verify(tagMapper, times(1)).insertTag(any(TagEntity.class));
        verify(assignmentTagMapper, times(1)).getAssignmentTagsByTagId(similarTagId);
        verify(assignmentTagMapper, times(1)).batchInsertAssignmentTags(anyList());
        verify(relevanceCalculationService, never()).calculateTagForAllAssignments(anyString(), anyString());
    }

    @Test
    void processGeneratedTag_WhenTagNotExistsAndNoSimilarTag_ShouldCreateNewTagAndCalculateRelevance() {
        // Arrange
        when(tagMapper.getTagByName(tagName)).thenReturn(null);
        when(tagMapper.insertTag(any(TagEntity.class))).thenReturn(1);
        // 修复：使用 doNothing() 来模拟 void 方法
        doNothing().when(relevanceCalculationService).calculateTagForAllAssignments(anyString(), anyString());

        // Act
        String result = tagProcessingService.processGeneratedTag(tagName, Collections.emptyList());

        // Assert
        assertNotNull(result);
        verify(tagMapper, times(1)).getTagByName(tagName);
        verify(tagMapper, times(1)).insertTag(any(TagEntity.class));
        verify(relevanceCalculationService, times(1)).calculateTagForAllAssignments(anyString(), anyString());
    }

    @Test
    void processGeneratedTag_WhenSimilarTagsNull_ShouldCreateNewTag() {
        // Arrange
        when(tagMapper.getTagByName(tagName)).thenReturn(null);
        when(tagMapper.insertTag(any(TagEntity.class))).thenReturn(1);
        doNothing().when(relevanceCalculationService).calculateTagForAllAssignments(anyString(), anyString());

        // Act
        String result = tagProcessingService.processGeneratedTag(tagName, null);

        // Assert
        assertNotNull(result);
        verify(tagMapper, times(1)).getTagByName(tagName);
        verify(tagMapper, times(1)).insertTag(any(TagEntity.class));
    }

    @Test
    void findSimilarTagId_WhenSimilarTagsExistInDatabase_ShouldReturnTagId() {
        // Arrange
        String similarTagName = "Java编程";
        String similarTagId = UUID.randomUUID().toString();
        TagEntity similarTag = new TagEntity();
        similarTag.setTagId(similarTagId);
        similarTag.setTagName(similarTagName);

        when(tagMapper.getTagByName(similarTagName)).thenReturn(similarTag);

        // Act
        String result = tagProcessingService.findSimilarTagId(tagName, Arrays.asList(similarTagName));

        // Assert
        assertEquals(similarTagId, result);
        verify(tagMapper, times(1)).getTagByName(similarTagName);
    }

    @Test
    void findSimilarTagId_WhenSimilarTagsNotExistInDatabase_ShouldReturnNull() {
        // Arrange
        String similarTagName = "Java编程";
        when(tagMapper.getTagByName(similarTagName)).thenReturn(null);

        // Act
        String result = tagProcessingService.findSimilarTagId(tagName, Arrays.asList(similarTagName));

        // Assert
        assertNull(result);
        verify(tagMapper, times(1)).getTagByName(similarTagName);
    }

    @Test
    void findSimilarTagId_WhenSimilarTagsEmpty_ShouldReturnNull() {
        // Act
        String result = tagProcessingService.findSimilarTagId(tagName, Collections.emptyList());

        // Assert
        assertNull(result);
        verify(tagMapper, never()).getTagByName(anyString());
    }

    @Test
    void findSimilarTagId_WhenSimilarTagsNull_ShouldReturnNull() {
        // Act
        String result = tagProcessingService.findSimilarTagId(tagName, null);

        // Assert
        assertNull(result);
        verify(tagMapper, never()).getTagByName(anyString());
    }

    @Test
    void copyAssignmentTagsFromSimilarTag_WhenSimilarTagHasAssignments_ShouldCopyRelations() {
        // Arrange
        String newTagId = UUID.randomUUID().toString();
        String similarTagId = UUID.randomUUID().toString();

        AssignmentTagEntity assignmentTag = new AssignmentTagEntity();
        assignmentTag.setId(UUID.randomUUID().toString());
        assignmentTag.setAssignmentId("assignment-1");
        assignmentTag.setTagId(similarTagId);
        assignmentTag.setRelevance(0.8);
        assignmentTag.setAssignmentWeight(1.0);

        List<AssignmentTagEntity> similarAssignmentTags = Arrays.asList(assignmentTag);

        when(assignmentTagMapper.getAssignmentTagsByTagId(similarTagId)).thenReturn(similarAssignmentTags);
        doNothing().when(assignmentTagMapper).batchInsertAssignmentTags(anyList());

        // Act
        tagProcessingService.copyAssignmentTagsFromSimilarTag(newTagId, similarTagId);

        // Assert
        verify(assignmentTagMapper, times(1)).getAssignmentTagsByTagId(similarTagId);
        verify(assignmentTagMapper, times(1)).batchInsertAssignmentTags(anyList());
    }

    @Test
    void copyAssignmentTagsFromSimilarTag_WhenSimilarTagNoAssignments_ShouldDoNothing() {
        // Arrange
        String newTagId = UUID.randomUUID().toString();
        String similarTagId = UUID.randomUUID().toString();

        when(assignmentTagMapper.getAssignmentTagsByTagId(similarTagId)).thenReturn(Collections.emptyList());

        // Act
        tagProcessingService.copyAssignmentTagsFromSimilarTag(newTagId, similarTagId);

        // Assert
        verify(assignmentTagMapper, times(1)).getAssignmentTagsByTagId(similarTagId);
        verify(assignmentTagMapper, never()).batchInsertAssignmentTags(anyList());
    }

    @Test
    void copyAssignmentTagsFromSimilarTag_WhenExceptionOccurs_ShouldThrowRuntimeException() {
        // Arrange
        String newTagId = UUID.randomUUID().toString();
        String similarTagId = UUID.randomUUID().toString();

        when(assignmentTagMapper.getAssignmentTagsByTagId(similarTagId)).thenThrow(new RuntimeException("Database error"));

        // Act & Assert
        RuntimeException exception = assertThrows(RuntimeException.class,
                () -> tagProcessingService.copyAssignmentTagsFromSimilarTag(newTagId, similarTagId));

        assertEquals("复制近似标签关联关系失败", exception.getMessage());
        verify(assignmentTagMapper, times(1)).getAssignmentTagsByTagId(similarTagId);
    }

    @Test
    void createTagEntity_ShouldCreateAndSaveTag() {
        // Arrange
        when(tagMapper.insertTag(any(TagEntity.class))).thenReturn(1);

        // Act
        String result = ReflectionTestUtils.invokeMethod(tagProcessingService, "createTagEntity", tagName);

        // Assert
        assertNotNull(result);
        verify(tagMapper, times(1)).insertTag(any(TagEntity.class));
    }

    @Test
    void createTagEntity_WhenExceptionOccurs_ShouldThrowRuntimeException() {
        // Arrange
        when(tagMapper.insertTag(any(TagEntity.class))).thenThrow(new RuntimeException("Insert failed"));

        // Act & Assert
        RuntimeException exception = assertThrows(RuntimeException.class,
                () -> ReflectionTestUtils.invokeMethod(tagProcessingService, "createTagEntity", tagName));

        assertTrue(exception.getMessage().contains("新增标签失败"));
        verify(tagMapper, times(1)).insertTag(any(TagEntity.class));
    }
}